package sk.stuba.fiit.repka.dp.owl.gui;

import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.MutableTreeNode;
import javax.swing.tree.TreePath;

import org.apache.log4j.Logger;

import sk.stuba.fiit.repka.dp.db.DBRatingManipulator;
import sk.stuba.fiit.repka.dp.db.DataManipulator;
import sk.stuba.fiit.repka.dp.db.EnumUtils;
import sk.stuba.fiit.repka.dp.gui.AddInputDialog;
import sk.stuba.fiit.repka.dp.gui.RecommendationsDialog;
import sk.stuba.fiit.repka.dp.owl.MyOWLClass;
import sk.stuba.fiit.repka.dp.owl.MyOWLDataProperty;
import sk.stuba.fiit.repka.dp.owl.OWLComponent;

public class DataPropPanel extends OWLPropertiesPanel {
	private static Logger logger = Logger.getLogger(DataPropPanel.class);
	
	private MainPanel parent;
	
	/**
	 * Create the panel.
	 */
	public DataPropPanel(MainPanel parent) {
		super(parent);
		
		this.parent = parent;
		
		this.getBtnAdd().addActionListener(new AddBTActionListener(this));
		this.getBtnRemove().addActionListener(new RemoveBTActionListener(this));
		this.getBtnDomain().addActionListener(new DomainBTActionListener(this));
		this.getBtnRange().addActionListener(new RangeBTActionListener(this));
		this.getBtnRecommendations().addActionListener(new RecommendationsBTActionListener(this));
		
		this.createTreeNodes(this.getRootNode(), this.parent.getDataPropertyList());
		this.getTree().addMouseListener(new TreeMouseListener(this));
	}
	
	private void addPropertyToList(String parentNodeName, String childName) {
		if("Top Property".equals(parentNodeName)) {
			this.parent.getDataPropertyList().add(new MyOWLDataProperty(childName));
			return;
		}
		
		MyOWLDataProperty prop = (MyOWLDataProperty)this.findOWLComponentByName(parentNodeName, this.parent.getDataPropertyList());
		prop.getSubComponents().add(new MyOWLDataProperty(childName));
	}
	
	//Map classes as Domains to property
	private void addDomainsToProperty(String nameOfProperty, List<MyOWLClass> inputClasses) {
		MyOWLDataProperty prop = (MyOWLDataProperty) this.findOWLComponentByName(nameOfProperty, this.parent.getDataPropertyList());
		if (prop != null) {
			// we found property and we'll map all domain classes to it
			Iterator<MyOWLClass> iterClass = inputClasses.iterator();
			while (iterClass.hasNext()) {
				prop.getDomains().add(iterClass.next());
			}
		}
	}
	
	//Map classes or string as Ranges to Property
	private void addRangesToProperty(String nameOfProperty, List<String> ranges) {
		MyOWLDataProperty prop = (MyOWLDataProperty) this.findOWLComponentByName(nameOfProperty, this.parent.getDataPropertyList());
		if (prop != null) {
			// we found property and we'll map all domain classes to it
			Iterator<String> iter = ranges.iterator();
			while (iter.hasNext()) {
				prop.getRanges().add(iter.next());
			}
		}
	}
	
	private class AddBTActionListener implements ActionListener {
		private DataPropPanel p;
		public AddBTActionListener(DataPropPanel p) {
			this.p = p;
		}
		
		@Override
		public void actionPerformed(ActionEvent arg0) {
			AddInputDialog dialog = new AddInputDialog("Add new data property");
			String componentName = dialog.getOutput();
			if(componentName != null && !"".equals(componentName)) {
				String parentName = p.addNewNode(componentName);
				if(parentName != null) {
					p.addPropertyToList(parentName, componentName);
				}
			}
		}
	}
	
	private class RemoveBTActionListener implements ActionListener {
		private DataPropPanel p;
		public RemoveBTActionListener(DataPropPanel p) {
			this.p = p;
		}
		
		@Override
		public void actionPerformed(ActionEvent e) {
			String removedNode = p.removeCurrentNode();
			if("".equals(removedNode)) {
				return;
			}
			p.removeComponentFromList(removedNode, p.parent.getDataPropertyList());
		}
	}
	
	private class DomainBTActionListener implements ActionListener {
		private DataPropPanel p;
		public DomainBTActionListener(DataPropPanel p) {
			this.p = p;
		}
		
		@Override
		public void actionPerformed(ActionEvent e) {
			Toolkit toolkit = Toolkit.getDefaultToolkit();
			String selectedProperty = null;
			TreePath currentSelection = p.getTree().getSelectionPath();
			if (currentSelection != null) {
				DefaultMutableTreeNode currentNode = (DefaultMutableTreeNode) (currentSelection.getLastPathComponent());
				MutableTreeNode parent = (MutableTreeNode) (currentNode.getParent());
				if (parent != null) {
					selectedProperty = currentNode.getUserObject().toString();
				}
				if(selectedProperty != null && !"".equals(selectedProperty)) {
					SelectDomainDialog dialog = new SelectDomainDialog(p.parent.getOwlClassesList());
					p.addDomainsToProperty(selectedProperty, dialog.getOutputClasses()); //map domain to selected property
					MyOWLDataProperty prop = (MyOWLDataProperty)p.findOWLComponentByName(currentNode.getUserObject().toString(), p.parent.getDataPropertyList());
					p.fillDomainPanel(prop);
				} else {
					toolkit.beep();
				}
			}
		}
	}
	
	private class RangeBTActionListener implements ActionListener {
		private DataPropPanel p;
		public RangeBTActionListener(DataPropPanel p) {
			this.p = p;
		}
		
		@Override
		public void actionPerformed(ActionEvent e) {
			Toolkit toolkit = Toolkit.getDefaultToolkit();
			String selectedProperty = null;
			TreePath currentSelection = p.getTree().getSelectionPath();
			if (currentSelection != null) {
				DefaultMutableTreeNode currentNode = (DefaultMutableTreeNode) (currentSelection.getLastPathComponent());
				MutableTreeNode parent = (MutableTreeNode) (currentNode.getParent());
				if (parent != null) {
					selectedProperty = currentNode.getUserObject().toString();
				}
				if(selectedProperty != null && !"".equals(selectedProperty)) {
					SelectRangeDialog dialog = new SelectRangeDialog(p.parent.getOwlClassesList(), false, true);
					p.addRangesToProperty(selectedProperty, dialog.getOutputRanges()); //map range to selected property
					MyOWLDataProperty prop = (MyOWLDataProperty)p.findOWLComponentByName(currentNode.getUserObject().toString(), p.parent.getDataPropertyList());
					p.fillRangePanel(prop);
				} else {
					toolkit.beep();
				}
			}
		}
	}
	
	private class RecommendationsBTActionListener implements ActionListener {
		private DataPropPanel p;
		private List<String> dataNames;
		
		public RecommendationsBTActionListener(DataPropPanel p) {
			this.p = p;
			this.dataNames = new ArrayList<String>();
		}
		
		private void fillDataNames(List<? extends OWLComponent> classes) {
			Iterator<? extends OWLComponent> iter = classes.iterator();
			while(iter.hasNext()) {
				MyOWLDataProperty d = (MyOWLDataProperty)iter.next();
				this.dataNames.add(d.getName());
				if(d.hasSubComponent()) {
					this.fillDataNames(d.getSubComponents());
				}
			}
		}
		
		@Override
		public void actionPerformed(ActionEvent e) {
			DataManipulator manipulator = new DBRatingManipulator(this.p.parent.getMainWindow().getDBController());
			this.dataNames = new ArrayList<String>();
			this.fillDataNames(p.parent.getDataPropertyList());
			try {
				List<String> reco = ((DBRatingManipulator)manipulator).getRecommendations(dataNames, EnumUtils.ATTR_TYPE_DATAPROP);
				RecommendationsDialog rdialog = new RecommendationsDialog(reco);
				List<String> selectedRecommendations = rdialog.getSelectedRecommendations();
				if (selectedRecommendations.size() > 0) {
					for (String s : selectedRecommendations) {
						String parentName = p.addNewNode(s);
						if (parentName != null) {
							p.addPropertyToList(parentName, s);
						}
						p.parent.getUsedRecommendations().add(s); // add used recommendations to list
					}
				}
			} catch (SQLException e1) {
				logger.error("Error during creating recommendations");
				e1.printStackTrace();
			}
		}
	}
	
	private class TreeMouseListener implements MouseListener {
		private DataPropPanel p;
		public TreeMouseListener(DataPropPanel p) {
			this.p = p;
		}
		
		@Override
		public void mouseClicked(MouseEvent e) {
			TreePath currentSelection = p.getTree().getPathForLocation(e.getX(), e.getY());
			if(currentSelection != null) {
				DefaultMutableTreeNode currentNode = (DefaultMutableTreeNode) (currentSelection.getLastPathComponent());
				MutableTreeNode parent = (MutableTreeNode) (currentNode.getParent());
				if (parent != null) {
					MyOWLDataProperty prop = (MyOWLDataProperty)p.findOWLComponentByName(currentNode.getUserObject().toString(), p.parent.getDataPropertyList());
					if(prop != null) {
						p.fillDomainPanel(prop);
						p.fillRangePanel(prop);
					}
				}
			}
		}

		@Override
		public void mouseEntered(MouseEvent arg0) {}

		@Override
		public void mouseExited(MouseEvent arg0) {}

		@Override
		public void mousePressed(MouseEvent arg0) {}

		@Override
		public void mouseReleased(MouseEvent arg0) {}
	}
}
